import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import IA.Energia.Centrales;
import IA.Energia.Clientes;
import aima.search.framework.Problem;
import aima.search.framework.Search;
import aima.search.framework.SearchAgent;
import aima.search.informed.SimulatedAnnealingSearch;

/**
 * Experimento 3
 */
public class Experimento3 implements IExperiment {
	List<List<String>> result = new ArrayList<List<String>>();
	double prTipos[];
	double prContratos;
	int tiposCentrales[];
	int nclientes;
	int numreplicas;
	boolean operador[];
	int It; // El numero maximo de iteraciones
	int incIt;
	int finIt;
	int ItP; // El numero de iteraciones por cada paso de temperatura
	int incItP;
	int finItP;
	int K; // k
	int inck;
	int fink;
	double L; // Lambda
	double incLambda;
	double finLambda;
	String nombre;
	int solucionInicial;
	
	public Experimento3 (String nombre, boolean[] operadores, int numreplicas, int solucionInicial, int numClientes, int[] tiposcentrales, double pgarantizados, double[] ptipoclientes, int iter, int incItv, int finItv, int iterp, int incItPv, int finItpv, int ka, int inckv, int finkv, double lambda, double incLambdav, double finLambdav) {
		prTipos = ptipoclientes;
		prContratos = pgarantizados;
		tiposCentrales = tiposcentrales;
		nclientes = numClientes;
		this.numreplicas = numreplicas;
		operador = operadores;
		It = iter;
		ItP = iterp;
		K = ka;
		L = lambda;
		incIt = incItv;
		finIt = finItv;
		incItP = incItPv;
		finItP = finItpv;
		inck = inckv;
		fink = finkv;
		incLambda = incLambdav;
		finLambda = finLambdav;
		this.nombre = nombre;
		this.solucionInicial = solucionInicial;
	}
	
	@Override
	public void init() {
		result = new ArrayList<List<String>>();
	}

	@Override
	public void execute() {
		List<String> cols = new ArrayList<String>();
		cols.add("Nombre experimento;");
		cols.add("Algoritmo;");
		cols.add("Put;");
		cols.add("Delete;");
		cols.add("Move;");
		cols.add("Swap;");
		cols.add("Replica;");
		cols.add("Tipo Sol. Ini.;");
		cols.add("N clientes;");
		cols.add("Centrales Tipo A;");
		cols.add("Centrales Tipo B;");
		cols.add("Centrales Tipo C;");
		cols.add("% Garantizados;");
		cols.add("% tipo clientes G;");
		cols.add("% tipo clientes MG;");
		cols.add("% tipo clientes XG;");
		cols.add("Iteraciones");
		cols.add("Iteraciones por paso de temperatura");
		cols.add("K");
		cols.add("Lambda");
		cols.add("Tiempo ms");
		cols.add("Beneficio");
		cols.add("Nodos expandidos");
		result.add(cols);
		boolean cambiar = operador[0], 
				quitar = operador[1], 
				anadir = operador[2],
				intercambiar = operador[3];
		
		Clientes clientes = null;
		for (int nIt = It; nIt <= finIt; nIt += incIt) {
			for (int Ki = K; Ki <= fink; Ki += inck) {
				double Li = L;
				while(Li <= finLambda) {
					
					for(int i = 0; i < numreplicas; ++i) {
						
						cols.add(nombre);
						cols.add("SimulatedAnealling");
						cols.add(String.valueOf(operador[2]));
						cols.add(String.valueOf(operador[1]));
						cols.add(String.valueOf(operador[0]));
						cols.add(String.valueOf(operador[3]));
						cols.add(String.valueOf(i+1));
						cols.add(solucionInicial == 0 ? "linear" : solucionInicial == 1 ? "random" : "greedy");
						cols.add(String.valueOf(nclientes));
						cols.add(String.valueOf(tiposCentrales[0]));
						cols.add(String.valueOf(tiposCentrales[1]));
						cols.add(String.valueOf(tiposCentrales[2]));
						cols.add(String.valueOf(prContratos));
						cols.add(String.valueOf(prTipos[0]));
						cols.add(String.valueOf(prTipos[1]));
						cols.add(String.valueOf(prTipos[2]));
						cols.add(String.valueOf(nIt));
						cols.add(String.valueOf(ItP));
						cols.add(String.valueOf(Ki));
						cols.add(String.valueOf(Li));
						
						long tiempo = System.currentTimeMillis();
						int semilla = (int) Math.random() * 1000;
						
						try {
							clientes = new Clientes(nclientes, prTipos , prContratos, semilla);
						} catch (Exception e1) {
							System.out.println("ERROR AL GENERAR CLIENTES: " + e1.getMessage());
							System.exit(1);
						}
						
						Centrales centrales = null;
						
						try {
							centrales = new Centrales(tiposCentrales, semilla);
						} catch (Exception e1) {
							System.out.println("ERROR AL GENERAR CENTRALES: " + e1.getMessage());
							System.exit(1);
						}
						
						Problem problemSA = new Problem(new Estado(clientes, centrales)
																, new EnergiaSuccessor(cambiar, quitar, anadir, intercambiar)
																, new EnergiaGoalTest()
																, new EnergiaHeuristica());
						
						Search searchSA = new SimulatedAnnealingSearch(nIt, ItP, Ki, Li);
						try {
							SearchAgent searchAgent = new SearchAgent(problemSA, searchSA);
							tiempo = System.currentTimeMillis() - tiempo;
							cols.add(String.valueOf(tiempo));
							Estado est = (Estado) searchAgent.getActions().get(0);
							double beneficio = est.gananciaClientes-est.costeCentrales -est.costeClientes;
							cols.add(String.valueOf(beneficio));
						} catch (Exception e) {
							System.out.println("ERROR: " + e.getMessage());
						}

						Li += incLambda;

						result.add(cols);
					}
				}
			}
		}
	}

	@Override
	public List<List<String>> getResult() {
		// TODO Auto-generated method stub
		return null;
	}
}
